package com.falcon.authority.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.falcon.authority.mapper.IRoleMapper;
import com.falcon.authority.mapper.IUserMapper;
import com.falcon.authority.mapper.IUserRoleMapper;
import com.falcon.authority.service.IRoleService;
import com.falcon.core.codec.IPasswordEncoder;
import com.falcon.core.domain.BaseRequest;
import com.falcon.core.service.AbsBaseService;
import com.falcon.authority.domain.po.RolePO;
import com.falcon.authority.domain.po.UserPO;
import com.falcon.authority.domain.po.UserRolePO;
import com.falcon.authority.domain.req.UserRequest;

import com.falcon.authority.service.IUserService;
import com.swan.mybatis.condition.Condition;
import com.swan.mybatis.condition.OpType;
import com.swan.mybatis.mapper.mapper.IBaseMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;


@Slf4j
@Service
public class UserService extends AbsBaseService<UserPO> implements IUserService {


    @Autowired
    private IUserMapper userMapper;

    @Autowired
    private IRoleMapper roleMapper;

    @Autowired
    private IUserRoleMapper userRoleMapper;

    @Autowired
    private IRoleService roleService;

    @Autowired
    private IPasswordEncoder passwordEncoder;

    @Override
    public IBaseMapper<Long, UserPO> getMapper() {
        return this.userMapper;
    }

    @Transactional
    @Override
    public Long save(BaseRequest baseRequest){

        UserRequest request = (UserRequest) baseRequest;

        if (Objects.nonNull(request.getRoleIds()) && !request.getRoleIds().isEmpty()) {
            this.validateRoleId(request.getRoleIds());
        }

        UserPO userPO = BeanUtil.copyProperties(request, UserPO.class);
        userPO.setPassword(this.passwordEncoder.encode(userPO.getPassword()));

        // 保存主表
        this.getMapper().insertNotNull(userPO);

        // 保存关系表
        this.saveUserRole(userPO.getId(), request.getRoleIds());

        return userPO.getId();
    }

    @Transactional
    @Override
    public Boolean update(Long id, BaseRequest baseRequest){

        UserRequest request = (UserRequest) baseRequest;

        this.validateRoleId(request.getRoleIds());

        // 更新主表
        UserPO userPO = BeanUtil.copyProperties(request, UserPO.class);
        userPO.setId(id);
        if (StringUtils.isNotEmpty(userPO.getPassword())) {
            userPO.setPassword(this.passwordEncoder.encode(userPO.getPassword()));
        }
        boolean success = this.getMapper().updateNotNull(userPO);

        // 处理关系表:先删后增
        this.userRoleMapper.deleteList(Condition.newInstance().and(UserRolePO.Fields.userId, OpType.equals, id));
        this.saveUserRole(id, request.getRoleIds());

        return success;
    }

    private List<RolePO> validateRoleId(List<Long> roleIds) {
        // 查询角色列表
        List<RolePO> rolePOS = this.roleMapper.selectListByIds(roleIds);

        // 校验参数
        Set<Long> findIds = rolePOS.stream().map(RolePO::getId).collect(Collectors.toSet());
        Long notExtId = roleIds.stream().filter(roleId -> !findIds.contains(roleId)).findAny().orElse(null);

        return rolePOS;
    }

    private void saveUserRole(Long userId, List<Long> roleIds) {
        if (Objects.isNull(roleIds) || roleIds.isEmpty()) {
            return;
        }
        roleIds.stream()
                .map(roleId -> new UserRolePO().setUserId(userId).setRoleId(roleId))
                .forEach(this.userRoleMapper::insertNotNull);
    }

}

